﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using SaiLing.Domain.Persistence.Relational;
using SaiLing.Domain.Specification;

namespace SaiLing.Repository
{
    public interface IRepository<T> where T : IEntity, new()
    {
        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <returns></returns>
        IQueryable<T> All<TS>(Expression<Func<T, TS>> orderByExpression, bool isDesc = true);

        /// <summary>
        /// 数据分页的方法
        /// </summary>
        /// <typeparam name="TS"></typeparam>
        /// <param name="pageIndex">当前页码</param>
        /// <param name="pageSize">每页显示条数</param>
        /// <param name="specification">数据查询条件表达式</param>
        /// <param name="orderByExpression">排序的条件表达式</param>
        /// <param name="isDesc">是否为倒序</param>
        /// <param name="asNoTracking">DbContext是否不跟踪查询出的实体</param>
        /// <returns></returns>
        IPagedList<T> PageList<TS>(int pageIndex, int pageSize, ISpecification<T> specification, Expression<Func<T, TS>> orderByExpression, bool isDesc, bool? asNoTracking = true);

        /// <summary>
        /// 得到所有数据
        /// </summary>
        /// <returns></returns>
        IEnumerable<T> GetAll(bool? asNoTracking = true);

        /// <summary>
        /// 根据条件表达式取得相关数据
        /// </summary>
        /// <param name="specification">Lambda表达式</param>
        /// <param name="asNoTracking">是否不跟踪实体</param>
        /// <returns></returns>
       IEnumerable<T> GetMany(ISpecification<T> specification, bool? asNoTracking = true);

        /// <summary>
        /// 取得记录数
        /// </summary>
        /// <returns></returns>
        int GetCount();

        /// <summary>
        /// 根据条件取得记录数
        /// </summary>
        /// <param name="specification"></param>
        /// <returns></returns>
        int GetCount(ISpecification<T> specification);

        /// <summary>
        /// 根据条件表达式取得指定条数的数据
        /// </summary>
        /// <typeparam name="TS"></typeparam>
        /// <param name="topN">返回的数据条数</param>
        /// <param name="specification">Lambda表达式</param>
        /// <param name="orderByExpression">Lambda表达式</param>
        /// <param name="isDesc"></param>
        /// <param name="asNoTracking"></param>
        /// <returns></returns>
        IEnumerable<T> GetListByTopN<TS>(int topN, ISpecification<T> specification, Expression<Func<T, TS>> orderByExpression, bool isDesc, bool? asNoTracking = true);

        /// <summary>
        /// 返回指定条件的数据   最多返回一条
        /// </summary>
        /// <param name="specification"></param>
        /// <param name="asNoTracking"></param>
        /// <returns></returns>
        Task<T> GetByCondition(ISpecification<T> specification, bool? asNoTracking = false);

        /// <summary>
        /// 返回指定标识的实体
        /// </summary>
        /// <param name="key">唯一标识</param>
        /// <returns></returns>
        Task<T> GetByKey(object key);

        /// <summary>
        /// 将实体数据保存到数据库中
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task Add(T entity);

        /// <summary>
        /// 更新数据数据库中的一条数据  根据主键值
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        void Modify(T entity);

        /// <summary>
        /// 更新实体的指定属性
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        void Update(T entity, params Expression<Func<T, object>>[] properties);


        /// <summary>
        /// 从数据库中删除数据(物理删除)   仅用于同一上下文的集合对象有效
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        void Remove(T entity);

        /// <summary>
        /// 删除指定条件的数据(物理删除)
        /// </summary>
        /// <param name="specification"></param>
        /// <returns></returns>
        Task Remove(ISpecification<T> specification);
        /// <summary>
        /// 从数据库删除数据(逻辑删除)
        /// </summary>
        /// <param name="entity"></param>
        void LogicRemove(T entity);

        /// <summary>
        /// 删除指定条件的数据(逻辑删除)
        /// </summary>
        /// <param name="specification"></param>
        Task LogicRemove(ISpecification<T> specification);

        /// <summary>
        /// 判断指定条件的数据是否存在
        /// </summary>
        /// <param name="specification"></param>
        /// <returns></returns>
        Task<bool> ExistsAsync(ISpecification<T> specification);
    }
}
